package com.example.chat.viewmodel

import android.content.Context
import android.util.Log
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.chat.navigation.NavigationController
import com.example.chat.navigation.Screen
import com.example.featuresdk.navigation.INavigationMediator
import com.example.chat.model.Message
import com.example.chat.model.MessageStatus
import com.example.featuresdk.model.User
import com.example.chat.repository.MessageRepository
import com.example.chat.repository.TopicRepository
import com.example.featuresdk.vo.Status
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch
import java.sql.Timestamp
import javax.inject.Inject

/**
 * View model is the business logic layer responsible for
 * 1. Use repository (data access layer) to manage changes to data model (business data layer)
 * 2. Publish changes to uiState observed by View (Compose) which will reflect the changes
 * 3. Handle events from View and perform corresponding business logic (commands), e.g. calculation, validation
 */
@HiltViewModel
class TopicDetailViewModel
@Inject constructor(private val messageRepository: MessageRepository,
                    private val topicRepository: TopicRepository,
                    @ApplicationContext private val context: Context,
                    private val navigationMediator: INavigationMediator,
                    savedStateHandle: SavedStateHandle): ViewModel() {

    companion object{
        const val TAG = "TopicDetailViewModel"
    }
    private val topicId = savedStateHandle.get<Long>("id")!!

    val uiState = TopicDetailState()

    val uiCommands = object : TopicDetailCommands {

        override fun sendMessage(){

            val currentTimeMillis = System.currentTimeMillis()
            var messageContent = uiState.chatContent.value

            val messages = mutableListOf(
                Message(null,topicId, User.ME.id!!,
                messageContent,null, MessageStatus.Read,
                Timestamp(currentTimeMillis))
            )


            //just for simulation
            if(topicId < 10) {
                //TODO: decouple user id from topic id
                messageContent = "Thanks for the message!"
                messages.add(
                    Message(null,topicId, topicId,
                    messageContent,null, MessageStatus.Read,
                    Timestamp(currentTimeMillis))
                )
            }

            launch {
                messageRepository.create(messages)
                topicRepository.updateSummary(topicId,messageContent,Timestamp(currentTimeMillis))
            }

            uiState.chatContent.value = ""
        }

        override fun sendMessage(image: Int) {
            launch {
                val currentTimeMillis = System.currentTimeMillis()
                val message = Message(
                    null, topicId, User.ME.id!!,
                    null, image, MessageStatus.Read,
                    Timestamp(currentTimeMillis)
                )
                messageRepository.create(message)
            }
        }

        override fun openContactDetail(contactId: Long) {
            navigationMediator.navigate("contact/{id}/detail",contactId.toString()){
                popUpTo("contact/{id}/detail"){
                    inclusive = true
                }
                launchSingleTop = true
            }
        }

        override fun openTopicSetting(topicId: Long) {
            NavigationController.instance.navigate(Screen.TopicSetting, topicId.toString())
        }
    }

    init {
        Log.i(TAG,"init: $this, topicId=$topicId")

        launch {
            uiState.topic = topicRepository.getOne(topicId)
            uiState.messages = messageRepository.getUserMessage(topicId)
            messageRepository.updateStatus(MessageStatus.Read, topicId)
            topicRepository.resetCount(topicId)
        }
    }

    private fun launch(action: suspend ()->Unit){
        viewModelScope.launch {
            try {
                action()
            }catch (e: CancellationException){
                //ignore
            }
            catch (t: Throwable){
                uiState.status.value = Status.Error
                uiState.message.value = t.message?:""
                Log.e(TAG,"Error",t)
            }
        }
    }

    override fun onCleared() {
        Log.e(TAG,"onCleared(): $this, topicId=$topicId")

        //DO NOT launch coroutine here as it will be cancelled when the ViewModel is disposed
        //it will not succeed to reset the message count
//        launch {
//            topicRepository.resetCount(topicId)
//        }
        super.onCleared()
    }
}